home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Taifun / Taifun 040 (1987-11-15)(Ossowski, Stefan)(DE)(PD).zip / Taifun 040 (1987-11-15)(Ossowski, Stefan)(DE)(PD).adf / A68k / Symtab.c < prev    next >
C/C++ Source or Header  |  1989-01-18  |  28KB  |  924 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*              MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*          Copyright    (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*       Symbol table    manipulation - September 9, 1987        */
  8. /*                                    */
  9. /*   This program may be copied    for personal, non-commercial use    */
  10. /*   only, provided that the above copyright notice is included        */
  11. /*   on    all copies of the source code.    Copying    for any    other use   */
  12. /*   without the consent of the    author is prohibited.            */
  13. /*                                    */
  14. /*------------------------------------------------------------------*/
  15. /*                                    */
  16. /*        Originally published (in Modula-2) in            */
  17. /*        Dr.    Dobb's Journal, April, May, and June 1986.          */
  18. /*                                    */
  19. /*    AmigaDOS conversion copyright (c) 1987 by Charlie Gibbs.    */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include "a68kdef.h"
  25. #include "a68kglb.h"
  26.  
  27. long Value;    /* Passed from ReadSymTab to CalcValue */
  28.  
  29. /* Functions */
  30. extern int  Instructions(), ObjDir();
  31. extern int  GetInstModeSize(), GetMultReg();
  32. extern int  GetArgs(), GetAReg();
  33. extern long AddrBndW(),    AddrBndL();
  34. extern char *malloc();
  35. extern FILE *fopen();
  36.  
  37. int  LineParts(), GetField(), ReadSymTab(), GetSize(), OpenIncl();
  38. long GetValue(), CalcValue();
  39.  
  40.  
  41.  
  42. int OpenIncl (name, dirlist) char name[], dirlist[];
  43. /* Opens the file whose    name is    in "name".  The current
  44.     directory is tried first.  If that fails, the directory
  45.     names in "dirlist" (separated by commas) are then tried
  46.     until either a file    is found or the    list is    exhausted.
  47.     If the file    is found in a subdirectory, "name" is
  48.     modified to    include    the entire path    specification.
  49.     If another input file is open when this routine is called,
  50.     it is closed first.     Returns TRUE if successful, FALSE if not.  */
  51. {
  52.     register int i;
  53.     char dirname[MAXLINE];
  54.  
  55.     if (InFile != NULL)
  56.     fclose (InFile);    /* Close the inner file    */
  57.  
  58.     if ((InFile    = fopen    (name, "r")) != NULL)
  59.     return (TRUE);        /* Found it in current directory */
  60.  
  61.     i =    0;
  62.     while (dirlist[i] != '\0') {
  63.     i = GetField (dirlist, i, dirname);
  64.     if ((dirname[i-1] != '/') && (dirname[i-1] != ':'))
  65.         strcat (dirname, "/");      /* Slash after directory name */
  66.     strcat (dirname, name);
  67.     if ((InFile = fopen (dirname, "r")) != NULL) {
  68.         strcpy (name, dirname);    /* Return entire path */
  69.         return (TRUE);    /* Found it in a subdirectory */
  70.     }
  71.     if (dirlist[i] != '\0')
  72.         i++;        /* Skip    over separator and try again */
  73.     }
  74.     return (FALSE);        /* Couldn't find it anywhere */
  75. }
  76.  
  77.  
  78.  
  79. int LineParts (dummy) int dummy;
  80. /* Gets    the next statement and extracts    its component parts.
  81.     If end of file is reached, and we're in a macro or include
  82.     file, the file is closed and the next outermost file is
  83.     continued.    If we have reached the end of the source file,
  84.     or encounter an ENDM or MEXIT directive, the current input
  85.     file closed    and TRUE is returned.
  86.  
  87.     If we're in a user macro (indicated by UPtr being nonzero),
  88.     we'll get the next statement from the save area in memory instead.
  89.  
  90.     Macro arguments, if    any, are substituted.
  91.  
  92.     LineCount is incremented if    a statement was    successfully read.
  93.  
  94.     If this is the first call of this routine (i.e. LineCount is zero)
  95.     and    HeaderFN is not    a null string, we'll return an INCLUDE statement
  96.     requesting the specified header file, rather than reading the first
  97.     statement from the source file.
  98.  
  99.     The    following fields are set up:
  100.     Line    - statement line image
  101.     Label    - instruction label (without trailing colon)
  102.     OpCode    - instruction mnemonic (converted to upper case)
  103.     SrcOp    - first    (source) operand
  104.     DestOp    - second (destination) operand
  105.     Size    - size from OpCode
  106.     SrcLoc    - displacement to start    of source operand
  107.     DestLoc    - displacement to start    of destination operand
  108.     InFNum    - decremented if end of    file is    reached
  109.     InF    - incremented if end of    file is    reached
  110.     LabLine    - set to LineCount if this line    is labeled
  111.             (unless    it's a local label)
  112.                                 */
  113. {
  114.     register int i, j, c;
  115.     register char *argptr;
  116.     char subline[MAXLINE];
  117.  
  118.     while (1) {    /* Repeat until    we get something (not end of INCLUDE) */
  119.     Line[0]    = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] =    '\0';
  120.     OpLoc =    SrcLoc = DestLoc = 0;
  121.  
  122.     if ((LineCount==0) && (HeaderFN[0])) {    /* Header file */
  123.         strcpy (Line, "        INCLUDE ");  /* Make an INCLUDE stmt. */
  124.         strcat (Line, HeaderFN);
  125.         strcat (Line, "        ;Generated for header file");
  126.         strcpy (OpCode, "INCLUDE"); /* Dummy op code */
  127.         OpLoc = 8;
  128.         strcpy (SrcOp, HeaderFN);    /* Dummy source    operand    */
  129.         SrcLoc = 16;
  130.         LineCount++;
  131.         errlim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  132.         PrntAddr = FALSE;
  133.         return (FALSE);
  134.     }
  135.  
  136.     if (InF->UPtr != 0) {            /* User    macro input */
  137.         strcpy (Line, InF->UPtr);
  138.         InF->UPtr += strlen    (Line) + 1;
  139.         c =    '\n';
  140.     } else {                /* Normal file input */
  141.         i =    0;
  142.         while ((c=getc(InFile)) != '\n') {  /* Get Line, expanding tabs */
  143.         if (c == 26)
  144.             c =    EOF;            /* Catch MS-DOS    EOF char. */
  145.         if (c == EOF) {
  146.             if (i > 0) {        /* Last    line has no \n -   */
  147.             c = ungetc (c, InFile);    /*  push back the EOF and  */
  148.             c = '\n';               /*  process the last line. */
  149.             }
  150.             break;
  151.         }
  152.         if ((i < (MAXLINE - 1))    && (c != 13)) {    /* Ignore excess */
  153.             if (c != '\t')
  154.             Line[i++] = c;        /* Normal character */
  155.             else {
  156.             j = (i + 8) & ~7;    /* Expand tabs */
  157.             if (j >    (MAXLINE - 1))
  158.                 j =    MAXLINE    - 1;    /* Tabbed off the end */
  159.             while (i < j)
  160.                 Line[i++] =    ' ';
  161.             }
  162.         }
  163.         }
  164.         Line[i] = '\0';
  165.     }
  166.     if ((Line[0] !=    '\0') && (Line[0] != '*') && (Line[0] != ';')) {
  167.  
  168.         /* --------    Macro argument substitution routine -------- */
  169.  
  170.         i =    0;
  171.         while ((Line[i] != '\0') && (InF->NArg != -1)) {
  172.         if ((subline[i]    = Line[i]) != '\\') {
  173.             i++;
  174.             continue;
  175.         }
  176.         if (Line[i+1] == '@') { /* \@ - substitute macro number */
  177.             subline[i] = '.';
  178.             j =    InF->MCnt % 1000;
  179.             subline[i+1] = j / 100 + '0';
  180.             j =    j % 100;
  181.             subline[i+2] = j / 10 + '0';
  182.             subline[i+3] = j % 10 + '0';
  183.             subline[i+4] = '\0';
  184.             strcat (subline, &Line[i+2]); /* Remainder of Line */
  185.             strcpy (Line, subline);    /* Replace Line    */
  186.             i =    0;            /* Check for more */
  187.             continue;
  188.         }
  189.  
  190.         if (Line[i+1] <    '0' || Line[i+1] > '9') {
  191.             continue;        /* False alarm */
  192.         }
  193.  
  194.         subline[i++] = '\0';    /* Chop off first portion */
  195.         j = 0;            /* Get argument    index */
  196.         while ((Line[i]    >= '0') && (Line[i] <= '9')) {
  197.             j *= 10;
  198.             j += Line[i++] - '0';       /* Current digit */
  199.         }
  200.         if ((j > 0) && (j <= InF->NArg)) {
  201.             argptr = InF->NPtr;
  202.             while (j > 0) {        /* Find    argument */
  203.             argptr += strlen (argptr) + 1;
  204.             j--;
  205.             }
  206.             strcat (subline, argptr);    /* Insert it */
  207.         }
  208.         strcat (subline, &Line[i]);    /* Remainder of    Line */
  209.         strcpy (Line, subline);        /* Replace Line    */
  210.         i = 0;                /* Check for more */
  211.         }
  212.  
  213.         /* ------- Break up    Line into its component    parts ------- */
  214.  
  215.         i =    0;
  216.         if (Line[i]    != ' ')
  217.         i = GetField (Line, i, Label);        /* Label */
  218.         while ((j =    strlen(Label)) > 0) {
  219.         if (Label[j-1] != ':')
  220.             break;
  221.         Label[j-1] = '\0';      /* Strip trailing colon(s) */
  222.         }
  223.         while (Line[i] == ' ') i++;
  224.         if (Line[i]    != ';') {
  225.         OpLoc =    i;
  226.         i = GetField (Line, i, OpCode);        /* Mnemonic */
  227.         while (Line[i] == ' ') i++;
  228.         if ((Line[i] !=    ';') && (Line[i] != '\0')) {
  229.             SrcLoc = i;
  230.             i =    GetField (Line,    i, SrcOp);    /* Op1 (source)    */
  231.             if (Line[i]    == ',')
  232.             i++;
  233.             if ((Line[i]!=' ') && (Line[i]!='\0') && (Line[i]!=';')) {
  234.             DestLoc    = i;
  235.             i = GetField (Line, i, DestOp);    /* Op2 (dest.) */
  236.             }
  237.         }
  238.         }
  239.     }
  240.     if ((j = strlen    (OpCode)) == 0)
  241.         Size = S0;
  242.     else {
  243.         Size = GetSize (OpCode);    /* Instruction operand size */
  244.         for    (i = 0;    i < j; i++)        /* Convert OpCode */
  245.         OpCode[i] = toupper(OpCode[i]);    /*  to upper case */
  246.     }
  247.  
  248.     /* ------ If we    have reached the end of    a macro    or ------ */
  249.     /* ------ include file,    return to the calling file ------ */
  250.  
  251.     i = (c == EOF);                    /* End of file */
  252.     if ((Dir != Macro) && (SkipNest    == 0)) {    /* Macro exits */
  253.         i |= (strcmp (OpCode, "ENDM") == 0);
  254.         i |= (strcmp (OpCode, "MEXIT") == 0);
  255.     }
  256.  
  257.     if (!i)    {            /* Not end of file or macro */
  258.         if ((PrevDir == MacCall) &&    (strcmp    (OpCode, "MACRO") == 0))
  259.         continue;        /* Ignore macro    header */
  260.         if (SkipNest == 0)        /* We're not skipping */
  261.         break;            /* We got something */
  262.         else {
  263.         if (strcmp (OpCode, "ENDC") == 0) SkipNest--;
  264.         else if    (strcmp    (OpCode, "IFEQ") == 0) SkipNest++;
  265.         else if    (strcmp    (OpCode, "IFNE") == 0) SkipNest++;
  266.         else if    (strcmp    (OpCode, "IFGT") == 0) SkipNest++;
  267.         else if    (strcmp    (OpCode, "IFGE") == 0) SkipNest++;
  268.         else if    (strcmp    (OpCode, "IFLT") == 0) SkipNest++;
  269.         else if    (strcmp    (OpCode, "IFLE") == 0) SkipNest++;
  270.         else if    (strcmp    (OpCode, "IFC" ) == 0) SkipNest++;
  271.         else if    (strcmp    (OpCode, "IFNC") == 0) SkipNest++;
  272.         else if    (strcmp    (OpCode, "IFD" ) == 0) SkipNest++;
  273.         else if    (strcmp    (OpCode, "IFND") == 0) SkipNest++;
  274.         continue;
  275.         }
  276.     }
  277.     if (InFNum == 0)
  278.         break;            /* End of source file */
  279.     if (InF->UPtr == 0) {
  280.         fclose (InFile);        /* Close inner file */
  281.         InFile = NULL;
  282.     }
  283.     NextFNS    = InF->NPtr;        /* Release space on name stack */
  284.     InFNum--;            /* Return to outer file    */
  285.     InF++;
  286.     if (InFNum < OuterMac)
  287.         OuterMac = 0;        /* End of outer    macro */
  288.     if ((InF->UPtr == 0) &&    (InFile    == NULL)) {
  289.         InFile = fopen (InF->NPtr, "r");
  290.         fseek (InFile, InF->Pos, 0);
  291.     }
  292.     }
  293.     LineCount++;            /* Bump    line counter */
  294.     (InF->Line)++;
  295.     if (Label[0] != '\0')
  296.     if ((Label[0] <    '0') || (Label[0] > '9'))
  297.         LabLine = LineCount;    /* Save    line number of label */
  298.     if ((LineCount % 10) == 0) {
  299.     printf ("%4d\b\b\b\b", LineCount);      /* Display progress */
  300. #ifdef AZTEC_C
  301.     fflush (stdout);        /* Make    sure it    gets out */
  302. #endif
  303.     }
  304.     errlim = AddrAdv = InstSize    = nO = nS = nD = nX = 0;
  305.     PrntAddr = FALSE;
  306.  
  307.     return (c == EOF);
  308. }
  309.  
  310.  
  311.  
  312. int GetField (source, pos, dest) char source[],    dest[];    int pos;
  313. /* Gets    a field    from "source", starting at position "pos".
  314.     Result is returned in "dest".
  315.     Stops on the first comma, semicolon, or white space    not
  316.     enclosed within    apostrophes or parentheses.
  317.     Returns stopping location.
  318.     If already at end of "source", "dest" is set to null string. */
  319. {
  320.     register char *s;
  321.     register int j, parncnt, instring;
  322.  
  323.     s =    source + pos;    /* Use a pointer for speed */
  324.     instring = FALSE;
  325.     parncnt = j    = 0;
  326.  
  327.     while (*s) {
  328.     if (instring) {
  329.         dest[j++] =    *s;
  330.     } else {
  331.         if ((*s == ' ') || (*s == ';'))
  332.         break;
  333.         else if ((*s == ',') && (parncnt == 0))
  334.         break;
  335.         else
  336.         dest[j++] = *s;
  337.     }
  338.     if (*s == '(')
  339.         parncnt++;
  340.     else if    (*s == ')')
  341.         parncnt--;
  342.     else if    (*s == '\'')
  343.         instring = !instring;
  344.     s++;
  345.     }
  346.     dest[j] = '\0';
  347.     return (s -    source);
  348. }
  349.  
  350.  
  351.  
  352. AddMacLine (line) char *line;
  353. /* Adds    the line in "line" to the heap. */
  354. {
  355.     HeapSpace (strlen (line) + 1);    /* Make    sure we    have room */
  356.     strcpy (HeapLim, line);        /* Store the line */
  357.     HeapLim += strlen (line) + 1;    /* Update heap limit */
  358. }
  359.  
  360.  
  361.  
  362. long GetValue (operand,    loc) char operand[]; int loc;
  363. /* Determines value of expression */
  364. /* Hunk2 is set    to hunk    number of result (ABSHUNK if absolute).
  365.    If the expression consists solely of    self-defining terms,
  366.     DefLine2 is set    to zero.  Otherwise, DefLine2 is set
  367.     to the highest statement number    in which any symbol in
  368.     the expression was defined.  If    the expression contains
  369.     any undefined symbols, DefLine2    is set to 32767.
  370.     The    following code is based    on a regular-to-Polish expression
  371.     converter described in "A Guide to FORTRAN IV Programming"
  372.     by Daniel D. McCracken (John Wiley & Sons, Inc.    1965,
  373.     3rd printing August 1968).  However, rather than generating
  374.     the entire Polish expression, this routine will    evaluate
  375.     and combine two    terms as soon as an operator of    lower
  376.     precedence is encountered.                */
  377. {
  378.     register char *o, *s;
  379.     char tempop[MAXLINE];
  380.     int     oloc, parncnt,    nextprec, instring;
  381.     long templong;
  382.     struct TermStack *origterm;
  383.  
  384.     Hunk2 = ABSHUNK;
  385.     parncnt = DefLine2 = 0;
  386.     o =    NextFNS;
  387.     if ((templong = (o - Heap) & 3L) !=    0)
  388.     o += 4 - templong;
  389.     origterm = Term = (struct TermStack    *) o;    /* Term    stack */
  390.     Ops    = (struct OpStack *) InF;        /* Operator stack */
  391.     Ops--;
  392.     ParseSpace (0);
  393.     Ops->chr = ' ';     /* Prime the operator stack */
  394.     Ops->prec =    -1;
  395.     if ((char *) Ops < Low2)
  396.     Low2 = (char *)    Ops;
  397.  
  398.     /* Get all tokens.
  399.     Terms are evaluated, and operator precedence is    determined.
  400.     Left and right parentheses are given a precedence of
  401.         1 and 2 respectively.
  402.     Binary operators are given precedence values starting at 3.
  403.     Unary plus is ignored.
  404.     Unary minus is converted to zero minus the remainder of
  405.         of the expression -    its precedence is set to 9 to
  406.         ensure that    the simulated unary operator is    evaluated
  407.         before the remainder of the    expression.
  408.     Logical    not (~), being another unary operator, is converted
  409.         to -1 exclusive-ORed with the remainder of the expression.
  410.         Its    precedence is also set to 9.                */
  411.  
  412.     o =    operand;            /* Current position in operand */
  413.  
  414.     while (1) {
  415.     while (*o == '(') {             /* Left parenthesis */
  416.         Ops--;
  417.         ParseSpace (0);
  418.         Ops->chr  =    '(';
  419.         Ops->prec =    1;
  420.         if ((char *) Ops < Low2)
  421.         Low2 = (char *)    Ops;
  422.         parncnt++;
  423.         o++;
  424.     }
  425.     if ((*o    == '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
  426.         if (*o != '+') {    /* Ignore unary plus */
  427.         Ops--;
  428.         ParseSpace (sizeof (struct TermStack));
  429.         Term->value   =    (*o == '-') ? 0 : -1;   /* Dummy value */
  430.         Term->hunk    =    ABSHUNK;
  431.         Term->oploc   =    loc + (o - operand);
  432.         Term->defline =    0;
  433.         Term++;
  434.         if ((char *) Term > High2)
  435.             High2 = (char *) Term;
  436.         Ops->chr  = *o;        /* Now get the operator    itself */
  437.         Ops->prec = 9;        /* Do it ASAP */
  438.         if ((char *) Ops < Low2)
  439.             Low2 = (char *) Ops;
  440.         }
  441.         o++;
  442.         if (*o == '(')
  443.         continue;    /* Inner parenthesized expression */
  444.     }
  445.     oloc = loc + (o    - operand);
  446.  
  447.     s = tempop;                /* Get a term */
  448.     if (*o == '*') {        /* It's a location counter reference, */
  449.         *s++ = *o++;    /*   not a multiplication operator!   */
  450.     } else {
  451.         if (IsOperator (o) || (*o == '\0')) {
  452.         Error (oloc, OperErr);    /* Unexpected operator or no terms */
  453.         return (0L);
  454.         }
  455.         instring = FALSE;
  456.         while (*o) {
  457.         if (*o == '\'')
  458.             instring = !instring;   /* String delimiter    */
  459.         if (!instring && (IsOperator (o) || (*o    == '~')))
  460.             break;            /* Found an    operator - stop    */
  461.         *s++ = *o++;            /* Get a character */
  462.         }
  463.     }
  464.     *s = '\0';
  465.     ParseSpace (sizeof (struct TermStack));
  466.     Term->value   =    CalcValue (tempop, oloc);
  467.     Term->hunk    =    Hunk2;
  468.     Term->oploc   =    oloc;
  469.     Term->defline =    DefLine2;
  470.     Term++;
  471.     if ((char *) Term > High2)
  472.         High2 = (char *) Term;
  473.     Hunk2 =    DefLine2 = 0;
  474.  
  475.     while (*o == ')') {                     /* Right parenthesis */
  476.         if (parncnt    == 0) {
  477.         Error ((int) (loc + (o - operand)), OperErr);
  478.         return (0L);
  479.         }
  480.         CondCalc (2);        /* Unstack what    we can */
  481.         if (Ops->chr == '(')
  482.         Ops++;            /* Drop    paired parentheses */
  483.         else {
  484.         Ops--;
  485.         ParseSpace (0);
  486.         Ops->chr  = ')';        /* Stack parenthesis for now */
  487.         Ops->prec = 2;
  488.         if ((char *) Ops < Low2)
  489.             Low2 = (char *) Ops;
  490.         }
  491.         parncnt--;
  492.         o++;
  493.     }
  494.     if (*o)    {
  495.         if (!IsOperator (o)    || (*o == '(')) {
  496.         Error ((int) (loc + (o - operand)), OperErr);
  497.         return (0L);        /* Expected an operator    */
  498.         }
  499.         switch (*o)    {
  500.         case '+': nextprec = 3; break;
  501.         case '-': nextprec = 3; break;
  502.         case '*': nextprec = 4; break;
  503.         case '/': nextprec = 4; break;
  504.         case '&': nextprec = 5; break;
  505.         case '!': nextprec = 5; break;
  506.         case '<': nextprec = 6; break;
  507.         case '>': nextprec = 6; break;
  508.         }
  509.         CondCalc (nextprec);    /* Unstack what    we can */
  510.         Ops--;
  511.         ParseSpace (0);
  512.         Ops->chr  =    *o;        /* Stack the next operator */
  513.         Ops->prec =    nextprec;
  514.         if ((char *) Ops < Low2)
  515.         Low2 = (char *)    Ops;
  516.         if ((*o == '<') || (*o == '>'))
  517.         o++;    /* Skip    over two-character operator */
  518.         o++;
  519.     } else {
  520.         if (parncnt) {
  521.         Error ((int) (loc + (o - operand)), OperErr);
  522.         return (0L);    /* Too many left parentheses */
  523.         }
  524.         CondCalc (0);        /* Unstack what's left */
  525.         if (--Term != origterm)    /* Should be only one term left    */
  526.         Error (Term->oploc, OperErr);        /* Parser bug? */
  527.         Hunk2    = Term->hunk;
  528.         DefLine2 = Term->defline;
  529.         return (Term->value);    /* Final value */
  530.     }
  531.     }
  532. }
  533.  
  534.  
  535.  
  536. CondCalc (newprec) int newprec;
  537. /* As long as the top operator on the operator stack has a precedence
  538.     greater than or equal to the contents of "newprec", this routine
  539.     will pop the two top terms from the    term stack, combine them
  540.     according to the operator on the top of the    operator stack (which
  541.     is also popped), and push the result back onto the term stack. */
  542. {
  543.     while (Ops->prec >=    newprec) {    /* Unstack an operator */
  544.     Term -=    2;
  545.     if (Ops->chr ==    '+') {          /* Relocatable addition */
  546.         if (Term->hunk == ABSHUNK)
  547.         Term->hunk = (Term+1)->hunk;    /* A+R */
  548.         else if ((Term+1)->hunk != ABSHUNK)    {
  549.         Error ((Term+1)->oploc,    RelErr);    /* R+R - error */
  550.         Term->hunk = ABSHUNK;        /* Make    it absolute */
  551.         }
  552.     } else if (Ops->chr == '-') {           /* Subtraction */
  553.         if (Term->hunk == (Term+1)->hunk)
  554.         Term->hunk = ABSHUNK;        /* R-R - absolute */
  555.         else if (Term->hunk    != ABSHUNK) {        /* R-R across hunks    */
  556.         Error ((Term+1)->oploc,    RelErr);    /*    is an error -    */
  557.         Term->hunk = ABSHUNK;            /* make it absolute    */
  558.         }
  559.     } else if ((Term->hunk != ABSHUNK)
  560.     || ((Term+1)->hunk != ABSHUNK))    {
  561.         Error (Term->oploc,RelErr);        /* All other operations    */
  562.         Term->hunk = ABSHUNK;        /*   must be absolute    */
  563.     }
  564.     if ((Term+1)->defline >    Term->defline)    /* Definition */
  565.         Term->defline = (Term+1)->defline;    /*  line nos. */
  566.  
  567.     switch (Ops->chr) {        /* Perform the operation */
  568.     case '+':
  569.         Term->value    += (Term+1)->value;
  570.         break;
  571.     case '-':
  572.         Term->value    -= (Term+1)->value;
  573.         break;
  574.     case '*':
  575.         Term->value    *= (Term+1)->value;
  576.         break;
  577.     case '/':
  578.         if ((Term+1)->value)
  579.         Term->value /= (Term+1)->value;
  580.         else
  581.         Term->value = 0;     /*    Don't divide by zero */
  582.         break;
  583.     case '&':
  584.         Term->value    &= (Term+1)->value;
  585.         break;
  586.     case '!':
  587.         Term->value    |= (Term+1)->value;
  588.         break;
  589.     case '<':
  590.         Term->value    <<= (Term+1)->value;
  591.         break;
  592.     case '>':
  593.         Term->value    >>= (Term+1)->value;
  594.         break;
  595.     case '~':
  596.         Term->value    ^= (Term+1)->value;
  597.         break;
  598.     default:
  599.         Error (Term->oploc,    OperErr);    /* Parser bug? */
  600.         break;
  601.     }
  602.     Term++;
  603.     Ops++;
  604.     }
  605. }
  606.  
  607.  
  608.  
  609. int IsOperator (o) char    *o;
  610. /* Tests whether "o" points to a valid operator or parenthesis. */
  611. {
  612.     return ((*o    == '+')
  613.     ||  (*o    == '-')
  614.     ||  (*o    == '*')
  615.     ||  (*o    == '/')
  616.     ||  (*o    == '&')
  617.     ||  (*o    == '!')
  618.     || ((*o    == '<') && (*(o+1) == '<'))
  619.     || ((*o    == '>') && (*(o+1) == '>'))
  620.     ||  (*o    == '(')
  621.     ||  (*o    == ')'));
  622. }
  623.  
  624.  
  625.  
  626. long CalcValue (operand, loc) char operand[]; int loc;
  627. /* Evaluates a single term (called by GetValue).
  628.     Hunk2 receives relative hunk number    (ABSHUNK if absolute).
  629.     If the value is a symbol, DefLine2 is set to the line number
  630.     where it was defined, or 32767 if it is    undefined.
  631.     For self-defining terms, DefLine2 is set to zero.    */
  632. {
  633.     register long result;    /* Result is calculated    here */
  634.     register int  i, radix;
  635.     int     neg, numstart,    local;
  636.     char maxdig;    /* Highest valid digit in current radix    */
  637.  
  638.     local = FALSE;
  639.     if (neg = (operand[0] == '-'))
  640.     numstart = 1;            /* Negative value */
  641.     else {
  642.     numstart = 0;            /* Positive value */
  643.     i = strlen(operand) - 1;
  644.     if (operand[i] == '$') {
  645.         local = TRUE;        /* Assume it's a local label */
  646.         while (i > 0) {
  647.         i--;
  648.         if ((operand[i]    < '0') || (operand[i] > '9')) {
  649.             local = FALSE;    /* False alarm */
  650.             break;
  651.         }
  652.         }
  653.     }
  654.     }
  655.     Hunk2 = ABSHUNK;            /* Assume value    is absolute */
  656.     DefLine2 = 0;            /* and self-defining */
  657.  
  658.     if ((operand[numstart] >= '0') && (operand[numstart] <= '9')) {
  659.     radix =    10;        /* Decimal number */
  660.     maxdig = '9';
  661.     } else if (operand[numstart] == '$') {
  662.     radix =    16;        /* Hexadecimal number */
  663.     maxdig = '9';
  664.     } else if (operand[numstart] == '@') {
  665.     radix =    8;        /* Octal number    */
  666.     maxdig = '7';
  667.     } else if (operand[numstart] == '%') {
  668.     radix =    2;        /* Binary number */
  669.     maxdig = '1';
  670.     } else
  671.     radix =    0;        /* Not a number    */
  672.     if (local)
  673.     radix =    0;        /* Local variable - not    a number */
  674.  
  675.     if (radix != 0) {            /* Some    sort of    number */
  676.     result = 0;
  677.     if (radix != 10)
  678.         numstart++;            /* Allow for type character */
  679.     for (i = numstart; operand[i] != '\0'; i++) {
  680.         result *= radix;
  681.         if ((operand[i] >= '0') && (operand[i] <= maxdig))
  682.         result += (operand[i] -    '0');
  683.         else if (radix == 16)
  684.         if ((operand[i]    >= 'A') && (operand[i] <= 'F'))
  685.             result += (operand[i] - 'A' + 10);
  686.         else if    ((operand[i] >=    'a') && (operand[i] <= 'f'))
  687.             result += (operand[i] - 'a' + 10);
  688.         else
  689.             Error (loc + i, OperErr);
  690.         else
  691.         Error (loc + i,    OperErr);
  692.     }
  693.     } else if (operand[0] == '\'') {            /* Character value */
  694.     result = 0;
  695.     for (i = 1; operand[i] != '\''; i++) {
  696.         if (operand[i] == '\0') {
  697.         Error (loc + i,    OperErr);    /* End is missing */
  698.         break;
  699.         }
  700.         result = (result <<    8) + operand[i];
  701.     }
  702.     } else if ((operand[0] == '*') && (operand[1] == '\0')) {
  703.     result = AddrCnt;    /* Value of location counter */
  704.     Hunk2 =    CurrHunk;    /* Use current section's hunk number */
  705.     } else if (strcmp (operand,    "NARG") == 0) {
  706.     result = InF->NArg;        /* Number of arguments */
  707.     if (result == -1)
  708.         result = 0;            /* No arguments    outside    macros */
  709.     } else {
  710.     if (ReadSymTab (operand)) {    /* Look    up symbol */
  711.         AddRef (LineCount);        /* Found - add reference */
  712.         if (Sym->Flags & 0x60)
  713.         Error (loc, AddrErr);    /* Can't use a register equate */
  714.     } else
  715.         Error (loc,    Undef);        /* Undefined */
  716.     result = Value;
  717.     }
  718.     if (neg) {
  719.     result = -result;        /* Negative value */
  720.     if (Hunk2 != ABSHUNK)
  721.         Error (loc,    RelErr);    /* Must    be absolute */
  722.     }
  723.     return(result);
  724. }
  725.  
  726.  
  727.  
  728. AddSymTab (label, value, hunk, line, flags)
  729. char label[];
  730. long value, hunk;
  731. int line, flags;
  732. /* Inserts a new entry to the symbol table and updates NumSyms.
  733.    The insertion position is taken from    "Sym" - it must be
  734.     such that the table    will be    kept in    sequence by label.
  735.     "Sym" is set by "ReadSymTab".
  736.     If the label is a local label (i.e.    the first character is
  737.     numeric), the current contents of LabLine will be converted
  738.     to characters and appended to the label before it is added.    */
  739. {
  740.     register char *pj1,    *pj2, *psym;
  741.     char wlab[MAXLINE],    wnum[6];
  742.  
  743.     strcpy (wlab, label);
  744.     if ((label[0] >= '0') && (label[0] <= '9')) {
  745.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  746.     strcat (wlab, wnum);        /*    append LabLine      */
  747.     }
  748.     pj2    = (char    *) SymStart;
  749.     SymStart--;
  750.     pj1    = (char    *) SymStart;
  751.     HeapSpace (strlen(wlab)+1);    /* Make    sure we    have room */
  752.     psym = (char *) Sym;    /* Try for some    speed */
  753.     while (pj2 < psym)        /* Shift the table */
  754.     *pj1++ = *pj2++;
  755.     Sect--;            /* Adjust section pointer */
  756.     Sym--;            /* Insert to left of search point */
  757.     Sym->Nam   = HeapLim;    /* Pointer to symbol */
  758.     Sym->Val   = value;        /* Value */
  759.     Sym->Hunk  = hunk;        /* Hunk    number */
  760.     Sym->Defn  = line;        /* Statement number */
  761.     Sym->Flags = flags;        /* Flags */
  762.     Sym->Ref1  = 0;        /* Reference pointer */
  763.     NumSyms++;            /* Count symbols */
  764.     strcpy (HeapLim, wlab);    /* Store the symbol */
  765.     HeapLim += strlen(wlab)+1;    /* Update heap limit */
  766. }
  767.  
  768.  
  769.  
  770. int ReadSymTab (label) char label[];
  771. /* Searches the    symbol table for the given label.
  772.    If not found, points    Sym to where the new entry should
  773.      be    inserted and returns FALSE.
  774.    If found, points Sym    to the proper table entry,
  775.      and sets up the following fields:
  776.     Value     - value of symbol
  777.     Hunk2     - hunk    number in which    symbol resides
  778.            ABSHUNK if value is absolute
  779.            ones    complement of symbol table index if external
  780.     DefLine2 - statement number in which symbol was    defined
  781.             (32767 if undefined )
  782.     If the label is a local label (i.e.    the first character is
  783.     numeric), the current contents of LabLine will be converted
  784.     to characters and appended to the label before it is searched. */
  785. {
  786.     register int lower,    upper, mid, search;
  787.     char wlab[MAXLINE],    wnum[6];
  788.  
  789.     strcpy (wlab, label);
  790.     if ((label[0] >= '0') && (label[0] <= '9')) {
  791.     sprintf    (wnum, "%d", LabLine);  /* If it's a local label, */
  792.     strcat (wlab, wnum);        /*    append LabLine      */
  793.     }
  794.     for    (lower = 0, upper = NumSyms; lower < upper; ) {
  795.     mid = (lower + upper) /    2;
  796.     Sym = SymStart + mid;
  797.     search = strcmp    (wlab, Sym->Nam);
  798.     if (search < 0)
  799.         upper = mid;
  800.     else if    (search    > 0)
  801.         lower = mid    + 1;
  802.     else {
  803.         Value = Sym->Val;        /* Found it */
  804.         Hunk2 = Sym->Hunk &    0x0000FFFFL;
  805.         if (Hunk2 &    0x00008000L)
  806.         Hunk2 |= 0xFFFF0000L;    /* Extend sign */
  807.         DefLine2 = Sym->Defn;
  808.         return (TRUE);
  809.     }
  810.     }
  811.     Value = 0;            /* Didn't find it - */
  812.     Hunk2 = ABSHUNK;        /* set value to    absolute zero */
  813.     DefLine2 = 32767;
  814.     Sym    = SymStart + lower;    /* Insert a new    entry here */
  815.     return (FALSE);
  816. }
  817.  
  818.  
  819.  
  820. AddRef (linenum) int linenum;
  821. /* Adds    "linenum" to the list of references
  822.     for    the symbol pointed to by Sym.        */
  823. {
  824.     register int i;
  825.     register struct Ref    *ref, *prevref;
  826.  
  827.     if (!Pass2)
  828.     return;            /* Pass    2 only!    */
  829.     if (!XrefList)
  830.     return;            /* No cross-reference */
  831.     prevref = 0;
  832.     ref    = Sym->Ref1;
  833.     while (ref)    {        /* Chase pointers */
  834.     for (i = 0; i <    MAXREF;    i++) {        /* Scan reference entry */
  835.         if (ref->RefNum[i] == 0) {        /*    for an empty slot   */
  836.         ref->RefNum[i] = linenum;   /* Insert new line number */
  837.         return;
  838.         }
  839.     }
  840.     prevref    = ref;            /* Remember where we were */
  841.     ref = ref->NextRef;        /* Link    to the next entry */
  842.     }
  843.     HeapSpace (sizeof (struct Ref));    /* Find    space for a new    entry */
  844.     RefStart--;
  845.     RefStart->NextRef =    0;        /* Pointer to next entry */
  846.     RefStart->RefNum[0]    = linenum;    /* First reference in new entry    */
  847.     for    (i = 1;    i < MAXREF; i++)
  848.     RefStart->RefNum[i] = 0;    /* Clear remaining slots */
  849.     if (prevref    == 0)
  850.     Sym->Ref1 = RefStart;        /* Link    to first entry */
  851.     else
  852.     prevref->NextRef = RefStart;    /* Link    to next    entry */
  853. }
  854.  
  855.  
  856.  
  857. int GetSize (symbol) char symbol[];
  858. /* Determines size of opcode/operand: Byte, Word, Long */
  859. {
  860.     register int  i;
  861.     register char c;
  862.  
  863.     i =    0;
  864.     while (1) {
  865.     c = symbol[i++];
  866.     if ((c == '\0') || (c == '.'))
  867.         break;
  868.     }
  869.     if (c == '\0')
  870.     return(Word);     /* Default to size Word = 16 bits */
  871.     else {
  872.     c = toupper (symbol[i]);    /* Record size extension */
  873.     symbol[i - 1] =    '\0';           /* Chop size extension off */
  874.     if ((c == 'B') || (c == 'S'))   /* Byte or Short Branch/Jump */
  875.         return(Byte);
  876.     else if    (c == 'L')              /* Long */
  877.         return(Long);
  878.     else
  879.         return(Word);        /* Default to Word */
  880.     }
  881. }
  882.  
  883.  
  884.  
  885. HeapSpace (n) int n;
  886. /* Die if we can't find "n" bytes of free space on the heap. */
  887. {
  888.     if ((HeapLim + n) >    (Pass2 ? (char *) RefStart : (char *) SymStart)) {
  889.     printf ("    \n%4d   %s\n", LineCount, Line);
  890.     printf ("Primary heap overflow - assembly terminated.\n");
  891.     free (Heap);
  892.     free (Heap2);
  893.     exit(20);
  894.     }
  895. }
  896.  
  897.  
  898.  
  899. Heap2Space (n) int n;
  900. /* Works like HeapSpace, but on    the secondary heap. */
  901. {
  902.     if ((NextFNS + n) >    (char *) InF) {
  903.     printf ("    \n%4d   %s\n", LineCount, Line);
  904.     printf ("Secondary heap overflow - assembly terminated.\n");
  905.     free (Heap);
  906.     free (Heap2);
  907.     exit(20);
  908.     }
  909. }
  910.  
  911.  
  912.  
  913. ParseSpace (n) int n;
  914. /* Special version of Heap2Space for the expression parser */
  915. {
  916.     if (((char *) Term + n) > (char *) Ops) {
  917.     printf ("    \n%4d   %s\n", LineCount, Line);
  918.     printf ("Secondary heap overflow - assembly terminated.\n");
  919.     free (Heap);
  920.     free (Heap2);
  921.     exit(20);
  922.     }
  923. }
  924.